package com.learning.thread.juc.executor.base;

import com.google.common.collect.Lists;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * ClassName: ExecutorFirst
 * Description: ExecutorService
 * Date: 2016/11/26 17:45
 *
 * @author SAM SHO
 * @version V1.0
 */
public class ExecutorServiceApi {


    public void executeTest() {
        // 启动三个线程
        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 提交一个 Runnable  任务
        executor.execute(new InTaskThread());
        executor.execute(new InTaskThread());

        // 关闭线程池
        executor.shutdown();
    }

    public void submitTest() throws ExecutionException, InterruptedException {
        // 启动三个线程
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 提交一个 Callable 任务
        // 提交一个带有返回值的任务（Callable），返回值为Future，表示了任务的执行完成结果，Future.get()方法返回成功执行后的结果。
        // 如果你想要阻塞当前线程直到执行完成返回结果，那么你可以这样做：
        // result = exec.submit(aCallable).get();
        Future<String> future = executor.submit(new InTaskCallable());
        String s = future.get();

        // 关闭线程池
        executor.shutdown();
    }


    /**
     * 方法invokeAny and invokeAll 可以执行一组任务，
     * 等待至少一个任务或者多个任务完成（ExecutorCompletionService 扩展了这些方法的实现）
     *
     * @throws InterruptedException
     */
    public void batchTest() throws InterruptedException, ExecutionException, TimeoutException {
        // 启动三个线程
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 一个任务完成
        String s = executor.invokeAny(Lists.newArrayList(new InTaskCallable()));
        executor.invokeAny(Lists.newArrayList(new InTaskCallable()), 1000L, TimeUnit.SECONDS);


        // 多个任务完成
        List<Future<String>> futures = executor.invokeAll(Lists.newArrayList(new InTaskCallable()));
        executor.invokeAll(Lists.newArrayList(new InTaskCallable()), 1000L, TimeUnit.SECONDS);
    }

    /**
     * 判断状态
     *
     * @throws InterruptedException
     */
    public void statusTest() throws InterruptedException {
        // 启动三个线程
        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 提交一个 Runnable  任务
        executor.execute(new InTaskThread());

        // 如果线程池停止完成返回true
        executor.isShutdown();

        // 如果线程池停止完成返回true
        // 当所有的任务都停止了，返回true， 注意：只有调用 shutdown 或者 shutdownNow 才返回true
        executor.isTerminated();

        // 调用此方法，在shutdown请求发起后，除非以下任何一种情况发生，否则当前线程将一直到阻塞。
        // 1、所有任务执行完成
        // 2、超过超时时间
        // 3、当前线程被中断
        executor.awaitTermination(60, TimeUnit.SECONDS);
    }


    public void shutdownTest() {
        // 启动三个线程
        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 提交一个 Runnable  任务
        executor.execute(new InTaskThread());

        // 发起一个关闭请求，已提交的任务会执行，但不会接受新的任务请求了
        // 这个方法不会等待已提交的任务全部执行完成，如果你希望这样做，可以使用awaitTermination方法
        executor.shutdown();

        // 立即关闭
        // 这个方法会停掉所有执行中的任务，取消等待中的任务，返回等待执行的任务 的list
        // 方法不会等待执行中的任务停止，如果你希望这样做，可以使用awaitTermination方法
        List<Runnable> runnables = executor.shutdownNow();
    }

    /**
     * 关闭方法：Guava 提供,版本不同，略有出入
     * 首先通过调用shutdown方法来拒绝加入的任务，
     * 等待已提交的任务执行完成结束。如果没有成功，调用shutdownNow来取消暂停的任务
     *
     * @param service
     */
    public static boolean shutdownAndAwaitTermination(ExecutorService service, long timeout, TimeUnit unit) {
        // checkNotNull(unit);
        // Disable new tasks from being submitted
        service.shutdown();
        try {
            long halfTimeoutNanos = TimeUnit.NANOSECONDS.convert(timeout, unit) / 2;
            // Wait for half the duration of the timeout for existing tasks to terminate
            if (!service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS)) {
                // Cancel currently executing tasks
                service.shutdownNow();
                // Wait the other half of the timeout for tasks to respond to being cancelled
                service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS);
            }
        } catch (InterruptedException ie) {
            // Preserve interrupt status
            Thread.currentThread().interrupt();
            // (Re-)Cancel if current thread also interrupted
            service.shutdownNow();
        }
        return service.isTerminated();
    }


    class InTaskThread implements Runnable {

        @Override
        public void run() {

            while (true) {
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    class InTaskCallable implements Callable<String> {
        @Override
        public String call() throws Exception {
            System.out.println(Thread.currentThread().getName());

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return Thread.currentThread().getName();
        }
    }
}
